﻿using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System.Globalization;
using System.Runtime.InteropServices;
using System.ComponentModel.Design;
using Microsoft.Win32;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.SharePoint;
using EnvDTE;
using EnvDTE80;

namespace SPVSX.Common
{
    /// <summary>
    /// TODO: Comment
    /// 
    /// This code is a WIP and is in need of improved commenting, exception handling, and potentially
    /// factoring.  Please be nice.
    /// 
    /// Though this code is Open Source, in good faith it is requested that you consult the original author(s)
    /// before changing or re-using it for any public endeavour intended to provide similar functionality, or
    /// to fix simple bugs.  In other words, if you want to create SPVSX2, please let us know first.
    /// </summary>
    /// <remarks>@author Matt Smith, http://blog.mattsmith.co.nz</remarks>  
    public static class ISharePointProjectItemExtensions
    {
        // Returns all features in the given project (whether packaged or not that contain this SPI.
        public static List<ISharePointProjectFeature> ParentFeaturesInProject(this ISharePointProjectItem item, ISharePointProject project)
        {
            List<ISharePointProjectFeature> features = new List<ISharePointProjectFeature>();
            features.AddRange(
                  from feature
                    in project.Features
                  where feature.ProjectItems.Contains(item)
                  select feature
                );
            return features;
        }

        // Returns true if this SPI is packaged in the given project directly (i.e. not as part of a feature). 
        public static bool IsDirectPartOfProjectPackage(this ISharePointProjectItem item, ISharePointProject project)
        {
            return project.Package.ProjectItems.Contains(item);
        }

        // Returns true if this SPI is packaged in any project in the solution directly (i.e. not as part of a feature).
        public static bool IsDirectPartOfAnyProjectPackage(this ISharePointProjectItem item, ISharePointProjectService service)
        {
            return service.Projects.Any(p => p.Package.ProjectItems.Contains(item));
        }

        // Returns true if this SPI is included inside a feature that is itself packaged in the given project.
        public static bool IsPartOfPackagedProjectFeature(this ISharePointProjectItem item, ISharePointProject project)
        {
            return item.ParentFeaturesInProject(project).Any(feature => feature.IsPartOfProjectPackage(project));
        }

        // Returns true if this SPI is included inside a feature that is packaged in any project in the solution.
        public static bool IsPartOfAnyPackagedProjectFeature(this ISharePointProjectItem item, ISharePointProjectService service)
        {
            foreach (ISharePointProject project in service.Projects)
            {
                if (item.IsPartOfPackagedProjectFeature(project))
                {
                    return true;
                }
            }
            
            return false;
        }
        
        // Returns true if this SPI is packaged in the given project whether by feature or direct (e.g. mapped folder).
        public static bool IsPartOfProjectPackage(this ISharePointProjectItem item, ISharePointProject project)
        {
            return item.IsDirectPartOfProjectPackage(project) || item.IsPartOfPackagedProjectFeature(project);
        }

        // Returns true if this SPI is packaged in any project in the solution whether by feature or direct (e.g. mapped folder).
        public static bool IsPartOfAnyProjectPackage(this ISharePointProjectItem item, ISharePointProjectService service)
        {
            return item.IsDirectPartOfAnyProjectPackage(service) || item.IsPartOfAnyPackagedProjectFeature(service);
        }

        // Retrieves all projects in the solution where this SPI is packaged.
        public static IEnumerable<ISharePointProject> GetProjectsWhereInPackage(this ISharePointProjectItem item, ISharePointProjectService service)
        {
            List<ISharePointProject> pkgProjects = new List<ISharePointProject>();

            foreach (ISharePointProject project in service.Projects)
            {
                if (item.IsPartOfProjectPackage(project))
                {
                    pkgProjects.Add(project);
                }
            }

            return pkgProjects;
        }

        // Retrieves all packaged features this SPI is a part of within a specific project.
        public static IEnumerable<ISharePointProjectFeature> GetFeaturesWhereInPackage(this ISharePointProjectItem item, ISharePointProject project)
        {
            return item.ParentFeaturesInProject(project).Where(feature => feature.IsPartOfProjectPackage(project));
        }
        
        // Returns true if this Feature is packaged in the given project.
        public static bool IsPartOfProjectPackage(this ISharePointProjectFeature feature, ISharePointProject project)
        {
            return project.Package.Features.Contains(feature);
        }

        // Returns true if this Feature is packaged in any project in the solution.
        public static bool IsPartOfAnyProjectPackage(this ISharePointProjectFeature feature, ISharePointProjectService service)
        {
            return service.Projects.Any(p => p.Package.Features.Contains(feature));
        }

        // Retrieves all projects in the solution where this feature is packaged.
        public static IEnumerable<ISharePointProject> GetProjectsWhereInPackage(this ISharePointProjectFeature feature, ISharePointProjectService service)
        {
            return service.Projects.Where(p => p.Package.Features.Contains(feature));
        }
    }
}
